package com.itjeffrey.autocode.quartz.job;

import com.alibaba.fastjson.JSON;
import com.itjeffrey.autocode.anno.JobLogger;
import com.itjeffrey.autocode.anno.SchedulerJob;
import com.itjeffrey.autocode.bo.DateDiff;
import com.itjeffrey.autocode.common.ACContext;
import com.itjeffrey.autocode.common.BaseCommon;
import com.itjeffrey.autocode.common.Result;
import com.itjeffrey.autocode.constant.SysConstant;
import com.itjeffrey.autocode.entity.DbConnTbEntity;
import com.itjeffrey.autocode.mapper.DbConnTbMapper;
import com.itjeffrey.autocode.util.DateUtil;
import com.itjeffrey.autocode.util.SpringContextHolder;
import com.itjeffrey.autocode.websocket.BaseSocketServer;
import com.itjeffrey.autocode.websocket.WebSocketServerContainer;
import org.apache.commons.collections4.CollectionUtils;
import org.quartz.DisallowConcurrentExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 定时清理数据库连接缓存任务
 *
 * @From: Jeffrey
 * @Date: 2021/6/2
 */
@SchedulerJob
@Component(value = "TimedCleanUpConnCacheJob")
@DisallowConcurrentExecution //禁止并发执行
public class TimedCleanUpConnCacheJob extends BaseJob {

    private static Logger logger = LoggerFactory.getLogger(TimedCleanUpConnCacheJob.class);

    //init jwtUserDetails
    public TimedCleanUpConnCacheJob(){
        super();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @JobLogger(name = "定时清理数据库连接缓存任务", jobParams = "project=autocode,developer=jeffrey")
    public void execute(Object obj) {
        //set UserContext
        ACContext.setUserContext(jwtUserDetails);
        //query all DbConnTbs
        DbConnTbMapper dbConnTbMapper = SpringContextHolder.getBean(DbConnTbMapper.class);
        List<DbConnTbEntity> dbConnTbEntities = dbConnTbMapper.selectList(null);
        int rmCount = 0;
        if (CollectionUtils.isNotEmpty(dbConnTbEntities)) {
            //iterator
            //compare the connTime, if beyound the limit time, then remove from the connMap
            for(DbConnTbEntity dbConnTbEntity : dbConnTbEntities) {
                String dbName = dbConnTbEntity.getDbName();
                if(BaseCommon.connMap.containsKey(dbName)){
                    Date connTime = dbConnTbEntity.getConnTime();
                    DateDiff dateDiff = DateUtil.getDateDiff(connTime, new Date());
                    long diff = dateDiff.getDiff(); //ms
                    BigDecimal diffBD = new BigDecimal(diff);
                    BigDecimal cacheTimeoutBD = new BigDecimal(SysConstant.DB_CONN_CACHE_TIMEOUT);
                    BigDecimal mDiffBD = new BigDecimal(1000 * 60);
                    diffBD = diffBD.divide(mDiffBD, 7, BigDecimal.ROUND_HALF_UP);
                    //set the default limit time is 30 minus.
                    if(diffBD.compareTo(cacheTimeoutBD) > 0){
                        //remove conn cache
                        BaseCommon.connMap.remove(dbConnTbEntity.getDbName());
                        //update dbconntb `conn_sts`
                        dbConnTbEntity.setConnSts(SysConstant.DB_CONN_STS_0);
                        dbConnTbEntity.setUpdateUser(ACContext.getUserContext().getUsername());
                        dbConnTbEntity.setUpdateTime(new Date());
                        dbConnTbMapper.updateById(dbConnTbEntity);
                        //webSocket send notify
                        String ip = "127.0.0.1"; //TODO
                        try {
                            BaseSocketServer webSocketServer = WebSocketServerContainer.getSocketServer(ip, "WebSocketServer");
                            Assert.notNull(webSocketServer, "webSocketServer require not null!");
                            webSocketServer.sendMessage(JSON.toJSONString(Result.ok(BaseCommon.connMap.size())));
                        } catch (IOException e) {
                            logger.error("connection连接数发送客户端失败！");
                            e.printStackTrace();
                        }
                        logger.info("connection连接数[{}]成功发送客户端！", BaseCommon.connMap.size());
                        rmCount++;
                    }
                }
            }
        }
        logger.info("TimedCleanUpConnCacheJob execute END---totalDbConnCount:{}---removeDbConnCount:{}", BaseCommon
                .connMap.size(), rmCount);
    }

}
